package com.kexilo.exception.properties;

import java.time.Duration;
import java.util.ArrayList;
import java.util.List;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.NestedConfigurationProperty;

import jakarta.validation.Valid;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;

/**
 * 异常处理插件配置属性
 * 提供完善的配置选项和IDE智能提示
 * 
 * @author Kexilo
 */
@ConfigurationProperties(prefix = "kexilo.plugin.exception")
public class ExceptionProperties {
    
    /**
     * 存储策略
     */
    public enum StorageStrategy {
        NONE,       // 不存储
        DATABASE,   // 数据库存储
        FILE,       // 文件存储
        REDIS,      // Redis存储
        MIXED       // 混合存储
    }
    
    /**
     * 通知策略
     */
    public enum NotificationStrategy {
        NONE,       // 不通知
        EMAIL,      // 邮件通知
        SMS,        // 短信通知
        DINGTALK,   // 钉钉通知
        WEBHOOK,    // Webhook通知
        ALL         // 全部通知
    }
    
    /**
     * 处理模式
     */
    public enum ProcessingMode {
        SYNC,       // 同步处理
        ASYNC,      // 异步处理
        QUEUE       // 队列处理
    }
    
    /**
     * 是否启用异常处理插件
     */
    private boolean enabled = true;
    
    /**
     * 存储策略
     */
    private StorageStrategy storageStrategy = StorageStrategy.DATABASE;
    
    /**
     * 通知策略
     */
    private NotificationStrategy notificationStrategy = NotificationStrategy.EMAIL;
    
    /**
     * 处理模式
     */
    private ProcessingMode processingMode = ProcessingMode.ASYNC;
    
    /**
     * 是否启用全局异常处理
     */
    private boolean globalHandlerEnabled = true;
    
    /**
     * 是否启用异常拦截AOP
     */
    private boolean interceptorEnabled = false;
    
    /**
     * 是否启用死信队列
     */
    private boolean deadLetterQueueEnabled = true;
    
    /**
     * 是否启用异常去重
     */
    private boolean deduplicationEnabled = true;
    
    /**
     * 异常去重时间窗口
     */
    private Duration deduplicationWindow = Duration.ofMinutes(5);
    
    /**
     * 忽略的异常类型
     */
    private List<String> ignoreExceptionTypes = new ArrayList<>();
    
    /**
     * 忽略的异常类
     */
    private List<String> ignoreExceptionClasses = new ArrayList<>();
    
    /**
     * 忽略的URL模式
     */
    private List<String> ignoreUrlPatterns = new ArrayList<>();
    
    /**
     * 数据库配置
     */
    @Valid
    @NestedConfigurationProperty
    private DatabaseProperties database = new DatabaseProperties();
    
    /**
     * 文件配置
     */
    @Valid
    @NestedConfigurationProperty
    private FileProperties file = new FileProperties();
    
    /**
     * 通知配置
     */
    @Valid
    @NestedConfigurationProperty
    private NotificationProperties notification = new NotificationProperties();
    
    /**
     * 死信队列配置
     */
    @Valid
    @NestedConfigurationProperty
    private DeadLetterProperties deadLetter = new DeadLetterProperties();
    
    /**
     * 监控配置
     */
    @Valid
    @NestedConfigurationProperty
    private MonitorProperties monitor = new MonitorProperties();
    
    /**
     * 清理配置
     */
    @Valid
    @NestedConfigurationProperty
    private CleanupProperties cleanup = new CleanupProperties();
    
    /**
     * 数据库配置属性
     */
    public static class DatabaseProperties {
        /**
         * 异常表名
         */
        @NotBlank(message = "异常表名不能为空")
        private String exceptionTable = "sys_exception";
        
        /**
         * 是否启用批量插入
         */
        private boolean batchInsertEnabled = true;
        
        /**
         * 批量插入大小
         */
        @Min(value = 1, message = "批量插入大小必须大于0")
        private int batchSize = 100;
        
        /**
         * 批量刷新间隔
         */
        private Duration batchFlushInterval = Duration.ofSeconds(5);
        
        /**
         * 连接超时
         */
        private Duration connectionTimeout = Duration.ofSeconds(30);
        
        /**
         * 是否启用事务
         */
        private boolean transactionEnabled = true;
        
        // Getters and Setters
        public String getExceptionTable() { return exceptionTable; }
        public void setExceptionTable(String exceptionTable) { this.exceptionTable = exceptionTable; }
        
        public boolean isBatchInsertEnabled() { return batchInsertEnabled; }
        public void setBatchInsertEnabled(boolean batchInsertEnabled) { this.batchInsertEnabled = batchInsertEnabled; }
        
        public int getBatchSize() { return batchSize; }
        public void setBatchSize(int batchSize) { this.batchSize = batchSize; }
        
        public Duration getBatchFlushInterval() { return batchFlushInterval; }
        public void setBatchFlushInterval(Duration batchFlushInterval) { this.batchFlushInterval = batchFlushInterval; }
        
        public Duration getConnectionTimeout() { return connectionTimeout; }
        public void setConnectionTimeout(Duration connectionTimeout) { this.connectionTimeout = connectionTimeout; }
        
        public boolean isTransactionEnabled() { return transactionEnabled; }
        public void setTransactionEnabled(boolean transactionEnabled) { this.transactionEnabled = transactionEnabled; }
    }
    
    /**
     * 文件配置属性
     */
    public static class FileProperties {
        /**
         * 文件存储路径
         */
        private String storagePath = "./logs/exceptions/";
        
        /**
         * 文件名模式
         */
        private String filenamePattern = "exception-%date{yyyy-MM-dd}.log";
        
        /**
         * 文件编码
         */
        private String encoding = "UTF-8";
        
        /**
         * 最大文件大小
         */
        private String maxFileSize = "100MB";
        
        /**
         * 保留历史文件数量
         */
        @Min(value = 1, message = "保留历史文件数量必须大于0")
        private int maxHistory = 30;
        
        /**
         * 是否压缩历史文件
         */
        private boolean compressHistory = true;
        
        // Getters and Setters
        public String getStoragePath() { return storagePath; }
        public void setStoragePath(String storagePath) { this.storagePath = storagePath; }
        
        public String getFilenamePattern() { return filenamePattern; }
        public void setFilenamePattern(String filenamePattern) { this.filenamePattern = filenamePattern; }
        
        public String getEncoding() { return encoding; }
        public void setEncoding(String encoding) { this.encoding = encoding; }
        
        public String getMaxFileSize() { return maxFileSize; }
        public void setMaxFileSize(String maxFileSize) { this.maxFileSize = maxFileSize; }
        
        public int getMaxHistory() { return maxHistory; }
        public void setMaxHistory(int maxHistory) { this.maxHistory = maxHistory; }
        
        public boolean isCompressHistory() { return compressHistory; }
        public void setCompressHistory(boolean compressHistory) { this.compressHistory = compressHistory; }
    }
    
    /**
     * 通知配置属性
     */
    public static class NotificationProperties {
        /**
         * 是否启用邮件通知
         */
        private boolean emailEnabled = false;
        
        /**
         * 邮件接收人
         */
        private List<String> emailRecipients = new ArrayList<>();
        
        /**
         * 邮件主题模板
         */
        private String emailSubjectTemplate = "[Kexilo] 系统异常告警 - {exceptionType}";
        
        /**
         * 是否启用短信通知
         */
        private boolean smsEnabled = false;
        
        /**
         * 短信接收人
         */
        private List<String> smsRecipients = new ArrayList<>();
        
        /**
         * 是否启用钉钉通知
         */
        private boolean dingTalkEnabled = false;
        
        /**
         * 钉钉机器人WebhookURL
         */
        private String dingTalkWebhookUrl;
        
        /**
         * 钉钉机器人密钥
         */
        private String dingTalkSecret;
        
        /**
         * 是否启用Webhook通知
         */
        private boolean webhookEnabled = false;
        
        /**
         * Webhook URL
         */
        private String webhookUrl;
        
        /**
         * 通知频率限制（分钟）
         */
        @Min(value = 1, message = "通知频率限制必须大于0")
        private int rateLimitMinutes = 10;
        
        /**
         * 通知级别（只通知该级别以上的异常）
         */
        private String notificationLevel = "ERROR";
        
        // Getters and Setters
        public boolean isEmailEnabled() { return emailEnabled; }
        public void setEmailEnabled(boolean emailEnabled) { this.emailEnabled = emailEnabled; }
        
        public List<String> getEmailRecipients() { return emailRecipients; }
        public void setEmailRecipients(List<String> emailRecipients) { this.emailRecipients = emailRecipients; }
        
        public String getEmailSubjectTemplate() { return emailSubjectTemplate; }
        public void setEmailSubjectTemplate(String emailSubjectTemplate) { this.emailSubjectTemplate = emailSubjectTemplate; }
        
        public boolean isSmsEnabled() { return smsEnabled; }
        public void setSmsEnabled(boolean smsEnabled) { this.smsEnabled = smsEnabled; }
        
        public List<String> getSmsRecipients() { return smsRecipients; }
        public void setSmsRecipients(List<String> smsRecipients) { this.smsRecipients = smsRecipients; }
        
        public boolean isDingTalkEnabled() { return dingTalkEnabled; }
        public void setDingTalkEnabled(boolean dingTalkEnabled) { this.dingTalkEnabled = dingTalkEnabled; }
        
        public String getDingTalkWebhookUrl() { return dingTalkWebhookUrl; }
        public void setDingTalkWebhookUrl(String dingTalkWebhookUrl) { this.dingTalkWebhookUrl = dingTalkWebhookUrl; }
        
        public String getDingTalkSecret() { return dingTalkSecret; }
        public void setDingTalkSecret(String dingTalkSecret) { this.dingTalkSecret = dingTalkSecret; }
        
        public boolean isWebhookEnabled() { return webhookEnabled; }
        public void setWebhookEnabled(boolean webhookEnabled) { this.webhookEnabled = webhookEnabled; }
        
        public String getWebhookUrl() { return webhookUrl; }
        public void setWebhookUrl(String webhookUrl) { this.webhookUrl = webhookUrl; }
        
        public int getRateLimitMinutes() { return rateLimitMinutes; }
        public void setRateLimitMinutes(int rateLimitMinutes) { this.rateLimitMinutes = rateLimitMinutes; }
        
        public String getNotificationLevel() { return notificationLevel; }
        public void setNotificationLevel(String notificationLevel) { this.notificationLevel = notificationLevel; }
    }
    
    /**
     * 死信队列配置属性
     */
    public static class DeadLetterProperties {
        /**
         * 队列名称
         */
        private String queueName = "exception-dead-letter-queue";
        
        /**
         * 最大队列长度
         */
        @Min(value = 1, message = "最大队列长度必须大于0")
        private int maxQueueSize = 10000;
        
        /**
         * 重试次数
         */
        @Min(value = 1, message = "重试次数必须大于0")
        private int maxRetries = 3;
        
        /**
         * 重试间隔
         */
        private Duration retryInterval = Duration.ofMinutes(5);
        
        /**
         * 队列过期时间
         */
        private Duration expiry = Duration.ofDays(7);
        
        // Getters and Setters
        public String getQueueName() { return queueName; }
        public void setQueueName(String queueName) { this.queueName = queueName; }
        
        public int getMaxQueueSize() { return maxQueueSize; }
        public void setMaxQueueSize(int maxQueueSize) { this.maxQueueSize = maxQueueSize; }
        
        public int getMaxRetries() { return maxRetries; }
        public void setMaxRetries(int maxRetries) { this.maxRetries = maxRetries; }
        
        public Duration getRetryInterval() { return retryInterval; }
        public void setRetryInterval(Duration retryInterval) { this.retryInterval = retryInterval; }
        
        public Duration getExpiry() { return expiry; }
        public void setExpiry(Duration expiry) { this.expiry = expiry; }
    }
    
    /**
     * 监控配置属性
     */
    public static class MonitorProperties {
        /**
         * 是否启用监控
         */
        private boolean enabled = true;
        
        /**
         * 监控间隔
         */
        private Duration monitorInterval = Duration.ofMinutes(5);
        
        /**
         * 异常频率告警阈值（每分钟）
         */
        @Min(value = 1, message = "告警阈值必须大于0")
        private int frequencyAlertThreshold = 50;
        
        /**
         * 是否启用性能监控
         */
        private boolean performanceMonitorEnabled = true;
        
        /**
         * 监控数据保留时间
         */
        private Duration dataRetentionTime = Duration.ofDays(30);
        
        // Getters and Setters
        public boolean isEnabled() { return enabled; }
        public void setEnabled(boolean enabled) { this.enabled = enabled; }
        
        public Duration getMonitorInterval() { return monitorInterval; }
        public void setMonitorInterval(Duration monitorInterval) { this.monitorInterval = monitorInterval; }
        
        public int getFrequencyAlertThreshold() { return frequencyAlertThreshold; }
        public void setFrequencyAlertThreshold(int frequencyAlertThreshold) { this.frequencyAlertThreshold = frequencyAlertThreshold; }
        
        public boolean isPerformanceMonitorEnabled() { return performanceMonitorEnabled; }
        public void setPerformanceMonitorEnabled(boolean performanceMonitorEnabled) { this.performanceMonitorEnabled = performanceMonitorEnabled; }
        
        public Duration getDataRetentionTime() { return dataRetentionTime; }
        public void setDataRetentionTime(Duration dataRetentionTime) { this.dataRetentionTime = dataRetentionTime; }
    }
    
    /**
     * 清理配置属性
     */
    public static class CleanupProperties {
        /**
         * 是否启用自动清理
         */
        private boolean enabled = true;
        
        /**
         * 清理间隔
         */
        private Duration cleanupInterval = Duration.ofDays(1);
        
        /**
         * 数据保留天数
         */
        @Min(value = 1, message = "数据保留天数必须大于0")
        private int dataRetentionDays = 30;
        
        /**
         * 清理批次大小
         */
        @Min(value = 1, message = "清理批次大小必须大于0")
        private int batchSize = 1000;
        
        // Getters and Setters
        public boolean isEnabled() { return enabled; }
        public void setEnabled(boolean enabled) { this.enabled = enabled; }
        
        public Duration getCleanupInterval() { return cleanupInterval; }
        public void setCleanupInterval(Duration cleanupInterval) { this.cleanupInterval = cleanupInterval; }
        
        public int getDataRetentionDays() { return dataRetentionDays; }
        public void setDataRetentionDays(int dataRetentionDays) { this.dataRetentionDays = dataRetentionDays; }
        
        public int getBatchSize() { return batchSize; }
        public void setBatchSize(int batchSize) { this.batchSize = batchSize; }
    }
    
    // Main class Getters and Setters
    public boolean isEnabled() { return enabled; }
    public void setEnabled(boolean enabled) { this.enabled = enabled; }
    
    public StorageStrategy getStorageStrategy() { return storageStrategy; }
    public void setStorageStrategy(StorageStrategy storageStrategy) { this.storageStrategy = storageStrategy; }
    
    public NotificationStrategy getNotificationStrategy() { return notificationStrategy; }
    public void setNotificationStrategy(NotificationStrategy notificationStrategy) { this.notificationStrategy = notificationStrategy; }
    
    public ProcessingMode getProcessingMode() { return processingMode; }
    public void setProcessingMode(ProcessingMode processingMode) { this.processingMode = processingMode; }
    
    public boolean isGlobalHandlerEnabled() { return globalHandlerEnabled; }
    public void setGlobalHandlerEnabled(boolean globalHandlerEnabled) { this.globalHandlerEnabled = globalHandlerEnabled; }
    
    public boolean isInterceptorEnabled() { return interceptorEnabled; }
    public void setInterceptorEnabled(boolean interceptorEnabled) { this.interceptorEnabled = interceptorEnabled; }
    
    public boolean isDeadLetterQueueEnabled() { return deadLetterQueueEnabled; }
    public void setDeadLetterQueueEnabled(boolean deadLetterQueueEnabled) { this.deadLetterQueueEnabled = deadLetterQueueEnabled; }
    
    public boolean isDeduplicationEnabled() { return deduplicationEnabled; }
    public void setDeduplicationEnabled(boolean deduplicationEnabled) { this.deduplicationEnabled = deduplicationEnabled; }
    
    public Duration getDeduplicationWindow() { return deduplicationWindow; }
    public void setDeduplicationWindow(Duration deduplicationWindow) { this.deduplicationWindow = deduplicationWindow; }
    
    public List<String> getIgnoreExceptionTypes() { return ignoreExceptionTypes; }
    public void setIgnoreExceptionTypes(List<String> ignoreExceptionTypes) { this.ignoreExceptionTypes = ignoreExceptionTypes; }
    
    public List<String> getIgnoreExceptionClasses() { return ignoreExceptionClasses; }
    public void setIgnoreExceptionClasses(List<String> ignoreExceptionClasses) { this.ignoreExceptionClasses = ignoreExceptionClasses; }
    
    public List<String> getIgnoreUrlPatterns() { return ignoreUrlPatterns; }
    public void setIgnoreUrlPatterns(List<String> ignoreUrlPatterns) { this.ignoreUrlPatterns = ignoreUrlPatterns; }
    
    public DatabaseProperties getDatabase() { return database; }
    public void setDatabase(DatabaseProperties database) { this.database = database; }
    
    public FileProperties getFile() { return file; }
    public void setFile(FileProperties file) { this.file = file; }
    
    public NotificationProperties getNotification() { return notification; }
    public void setNotification(NotificationProperties notification) { this.notification = notification; }
    
    public DeadLetterProperties getDeadLetter() { return deadLetter; }
    public void setDeadLetter(DeadLetterProperties deadLetter) { this.deadLetter = deadLetter; }
    
    public MonitorProperties getMonitor() { return monitor; }
    public void setMonitor(MonitorProperties monitor) { this.monitor = monitor; }
    
    public CleanupProperties getCleanup() { return cleanup; }
    public void setCleanup(CleanupProperties cleanup) { this.cleanup = cleanup; }
}
